﻿using LogLib;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using KAImage.Config;

namespace KAImage.Algorithms
{
    public static class ImageExtends
    {
        internal static void SwapRGB(ref int a, ref int b)
        {
            a += b;
            b = a - b;
            a -= b;
        }

        internal static void CheckRGB(ref int Value)
        {
            if (Value < 0)
            {
                Value = 0;
            }              
            else if (Value > 255)
            {
                Value = 255;
            }                
        }

        internal static void SetHue(ref byte R, ref byte G, ref byte B, int hValue)
        {
            if (hValue == 0)
            {
                return;
            }
            if (R == B && B ==G)
            {
                return;
            }
            int intR = R;
            int intG = G;
            int intB = B;       
            

            //if (intR < intG)
            //{
            //    SwapRGB(ref intR, ref intG);
            //}
            //if (intR < intB)
            //{
            //    SwapRGB(ref intR, ref intB);
            //}
            //if (intB > intG)
            //{
            //    SwapRGB(ref intB, ref intG);
            //}

            int delta = intR - intB;
            if (delta <= 0)
                return;
            int entire = intR + intB;
            int H = 0, S, L = entire >> 1;
            if (L < 128)
            {
                S = delta * 255 / entire;
            }
            else
            {
                S = delta * 255 / (510 - entire);
            }
            if (intR == R && delta > 0)
            {
                H = (G - B) * 60 / delta;
            }
            else if (intR == G && delta > 0)
            {
                H = (B - R) * 60 / delta + 120;
            }
            else if (delta > 0)
            {
                H = (R - G) * 60 / delta + 240;
            }
            H += hValue;
            if (H < 0)
            {
                H += 360;
            }
            else if (H > 360)
            {
                H -= 360;
            }
            int index = H / 60;
            int extra = H % 60;
            if ((index & 1) > 0)
            {
                extra = 60 - extra;
            }
            extra = (extra * 255 + 30) / 60;
            intG = extra - (extra - 128) * (255 - S) / 255;
            int Lum = L - 128;
            if (Lum > 0)
            {
                intG += (((255 - intG) * Lum + 64) / 128);
            }
            else if (Lum < 0)
            {
                intG += (intG * Lum / 128);
            }
            if (intG < 0)
            {
                intG = 0;
            }
            else if (intG > 255)
            {
                intG = 255;
            }

            switch (index)
            {
                case 1:
                    SwapRGB(ref intR, ref intG);
                    break;
                case 2:
                    SwapRGB(ref intR, ref intB);
                    SwapRGB(ref intG, ref intB);
                    break;
                case 3:
                    SwapRGB(ref intR, ref intB);
                    break;
                case 4:
                    SwapRGB(ref intR, ref intG);
                    SwapRGB(ref intG, ref intB);
                    break;
                case 5:
                    SwapRGB(ref intG, ref intB);
                    break;
            }

            R = (byte)intR;
            G = (byte)intG;
            B = (byte)intB;
            //try
            //{
                
            //}
            //catch (Exception ex)
            //{
            //    Log.WriteAsync(ex.ToString());
            //}          
        }

        public static void AdjustHue(this Bitmap source, int delta)
        {
            //参数范围有效性判断
            if (delta < -180 || delta > 180)
            {
                throw new Exception("无效的Hue调整参数，参数范围∈[-180,180]");
            }             
            if (delta == 0)
            {
                return;
            }
            Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
            BitmapData bmpData = source.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            IntPtr ptr = bmpData.Scan0;
            int bytes = source.Width * source.Height * 4;
            //byte sr, sg, sb;    // RGB 
            byte[] rgbValues = new byte[bytes];
            Marshal.Copy(ptr, rgbValues, 0, bytes);
            Parallel.For(0, rgbValues.Length/4, index =>
            {
                int i = 4 * index;
                byte b = rgbValues[i];
                byte g = rgbValues[i + 1];
                byte r = rgbValues[i + 2];
                SetHue(ref r, ref g, ref b, delta);
                rgbValues[i] = b;
                rgbValues[i + 1] = g;
                rgbValues[i + 2] = r;
            });
            //for (int i = 0; i < rgbValues.Length; i = i + 4)
            //{
              
            //}
            Marshal.Copy(rgbValues, 0, ptr, bytes);
            source.UnlockBits(bmpData);
        }

        public static void AdjustLightness(this Bitmap source, int delta)
        {
            //参数范围有效性判断
            if (delta < -100 || delta > 100)
                throw new Exception("无效的参数，参数范围∈[-100,100]");
            if (delta == 0)
            {
                return;
            }
            Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
            BitmapData bmpData = source.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            IntPtr ptr = bmpData.Scan0;
            int bytes = source.Width * source.Height * 4;
            int sr, sg, sb;                           // 原始RGB 
            int dr, dg, db;                         // 结果RGB  
            delta = delta * 255 / 100;      // 缩放明度调整参数
            byte[] rgbValues = new byte[bytes];
            Marshal.Copy(ptr, rgbValues, 0, bytes);
            if(delta > 0)
            {
                for (int i = 0; i < rgbValues.Length; i = i + 4)
                {
                    sb = rgbValues[i];
                    sg = rgbValues[i + 1];
                    sr = rgbValues[i + 2];

                    db = sb + (255 - sb) * delta / 255;
                    dg = sg + (255 - sg) * delta / 255;
                    dr = sr + (255 - sr) * delta / 255;

                    rgbValues[i] = (byte)db;
                    rgbValues[i + 1] = (byte)dg;
                    rgbValues[i + 2] = (byte)dr;
                }
            }
            else
            {
                for (int i = 0; i < rgbValues.Length; i = i + 4)
                {
                    sb = rgbValues[i];
                    sg = rgbValues[i + 1];
                    sr = rgbValues[i + 2];

                    db = sb + sb * delta / 255;
                    dg = sg + sg * delta / 255;
                    dr = sr + sr * delta / 255;

                    rgbValues[i] = (byte)db;
                    rgbValues[i + 1] = (byte)dg;
                    rgbValues[i + 2] = (byte)dr;
                }
            }
            Marshal.Copy(rgbValues, 0, ptr, bytes);
            source.UnlockBits(bmpData);
        }

        public static void AdjustSaturation(this Bitmap source, int delta)
        {
            if (delta == 0)
            {
                return;
            }
            Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
            BitmapData bmpData = source.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            IntPtr ptr = bmpData.Scan0;
            int bytes = source.Width * source.Height * 4;
            byte[] rgbValues = new byte[bytes];
            Marshal.Copy(ptr, rgbValues, 0, bytes);

            //参数处理
            double dPercent = (double)delta / 100D;

            int sr, sg, sb;           // 原始RGB
            int dr, dg, db;         // 结果RGB  

            double dDelta;
            double dValue;
            double dL;
            double dS;
            double dAlpha;
            double dTemp;

            for (int i = 0; i < rgbValues.Length; i = i + 4)
            {
                sb = rgbValues[i];
                sg = rgbValues[i + 1];
                sr = rgbValues[i + 2];

                int max = Math.Max(sr, Math.Max(sg, sb));
                int min = Math.Min(sr, Math.Min(sg, sb));

                dDelta = (double)(max - min) / 255D;
                dValue = (double)(max + min) / 255D;

                //如果该像素点是灰色 不处理
                if (0 == dDelta)
                {
                    continue;
                }

                //按照公式计算明度L   [0,1]
                dL = dValue / 2;

                //按照公式计算饱和度S   [0,1]
                if (dL < 0.5)
                {
                    dS = dDelta / dValue;
                }
                else
                {
                    dS = dDelta / (2 - dValue);
                }

                //进行饱和度调整
                if (dPercent >= 0)
                {
                    if (dPercent + dS >= 1)
                    {
                        dAlpha = dS;
                    }
                    else
                    {
                        dAlpha = 1 - dPercent;
                    }
                    dAlpha = 1 / dAlpha - 1;
                    db = (int)(sb + (sb - dL * 255) * dAlpha);
                    dg = (int)(sg + (sg - dL * 255) * dAlpha);
                    dr = (int)(sr + (sr - dL * 255) * dAlpha);
                }
                else
                {
                    dAlpha = dPercent;
                    dTemp = dL * 255D;
                    db = (int)(dTemp + (sb - dTemp) * (1D + dAlpha));
                    dg = (int)(dTemp + (sg - dTemp) * (1D + dAlpha));
                    dr = (int)(dTemp + (sr - dTemp) * (1D + dAlpha));
                }
                rgbValues[i] = (byte)db;
                rgbValues[i + 1] = (byte)dg;
                rgbValues[i + 2] = (byte)dr;
            }
            Marshal.Copy(rgbValues, 0, ptr, bytes);
            source.UnlockBits(bmpData);
        }

        public static void SetHSLOffset(this Bitmap source, ImageHSLOffset option)
        {  
            // 用于调节HUE的对象
            HSLColor.Settings = option;
            HSLColor ctl = new HSLColor();
            ctl.InitActionArray();
            Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
            BitmapData bmpData = source.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            IntPtr ptr = bmpData.Scan0;
            int bytes = source.Width * source.Height * 4;
            byte sr, sg, sb;    // RGB 
            byte[] rgbValues = new byte[bytes];
            Marshal.Copy(ptr, rgbValues, 0, bytes);
            for (int i = 0; i < rgbValues.Length; i = i + 4)
            {
                sb = rgbValues[i];
                sg = rgbValues[i + 1];
                sr = rgbValues[i + 2];
                ctl.Reset(sr, sg, sb);
                ctl.SetHSLOffsets();
                rgbValues[i] = ctl.B;
                rgbValues[i + 1] = ctl.G;
                rgbValues[i + 2] = ctl.R;
            }               
            Marshal.Copy(rgbValues, 0, ptr, bytes);
            source.UnlockBits(bmpData);
        }

        public static void SetHueOffset(this Bitmap source, ImageHSLOffset settings)
        {
            // 用于调节HUE的对象
            HSLColor ctl = new HSLColor();
            Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
            BitmapData bmpData = source.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            IntPtr ptr = bmpData.Scan0;
            int bytes = source.Width * source.Height * 4;
            byte sr, sg, sb;    // RGB 
            byte[] rgbValues = new byte[bytes];
            Marshal.Copy(ptr, rgbValues, 0, bytes);
            for (int i = 0; i < rgbValues.Length; i = i + 4)
            {
                sb = rgbValues[i];
                sg = rgbValues[i + 1];
                sr = rgbValues[i + 2];
                ctl.Reset(sr, sg, sb);
                ctl.SetHueOffset();               
                rgbValues[i] = ctl.B;
                rgbValues[i + 1] = ctl.G;
                rgbValues[i + 2] = ctl.R;
            }
            Marshal.Copy(rgbValues, 0, ptr, bytes);
            source.UnlockBits(bmpData);
        }

        public static void SetSaturationOffset(this Bitmap source)
        {         
            Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
            BitmapData bmpData = source.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            IntPtr ptr = bmpData.Scan0;
            int bytes = source.Width * source.Height * 4;
            byte[] rgbValues = new byte[bytes];
            Marshal.Copy(ptr, rgbValues, 0, bytes);
            // 用于调节Saturation的对象
            HSLColor ctl = new HSLColor();
            int sr, sg, sb;           // 原始RGB  
            for (int i = 0; i < rgbValues.Length; i = i + 4)
            {
                sb = rgbValues[i];
                sg = rgbValues[i + 1];
                sr = rgbValues[i + 2];
                ctl.Reset(sr, sg, sb);
                if (ctl.IsGray)
                {
                    continue;
                }
                ctl.SetSaturationOffset();
                rgbValues[i] = ctl.B;
                rgbValues[i + 1] = ctl.G;
                rgbValues[i + 2] = ctl.R;
            }
            Marshal.Copy(rgbValues, 0, ptr, bytes);
            source.UnlockBits(bmpData);
        }

        public static void SetTotalLightnessOffset(this Bitmap source)
        {
            Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
            BitmapData bmpData = source.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            IntPtr ptr = bmpData.Scan0;
            int bytes = source.Width * source.Height * 4;
            int sr, sg, sb;                           // 原始RGB 
            byte[] rgbValues = new byte[bytes];
            Marshal.Copy(ptr, rgbValues, 0, bytes);
            // 用于调节HUE的对象
            HSLColor ctl = new HSLColor();
            for (int i = 0; i < rgbValues.Length; i = i + 4)
            {
                sb = rgbValues[i];
                sg = rgbValues[i + 1];
                sr = rgbValues[i + 2];
                ctl.Reset(sr, sg, sb);
                if (ctl.IsGray)
                {
                    continue;
                }
                ctl.SetTotalLightnessOffset();
                rgbValues[i] = ctl.B;
                rgbValues[i + 1] = ctl.G;
                rgbValues[i + 2] = ctl.R;
            }
            Marshal.Copy(rgbValues, 0, ptr, bytes);
            source.UnlockBits(bmpData);
        }

        public static void SetChannelLightnessOffset(this Bitmap source)
        {
            Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
            BitmapData bmpData = source.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            IntPtr ptr = bmpData.Scan0;
            int bytes = source.Width * source.Height * 4;
            int sr, sg, sb;                           // 原始RGB 
            byte[] rgbValues = new byte[bytes];
            Marshal.Copy(ptr, rgbValues, 0, bytes);
            // 用于调节HUE的对象
            HSLColor ctl = new HSLColor();
            for (int i = 0; i < rgbValues.Length; i = i + 4)
            {
                sb = rgbValues[i];
                sg = rgbValues[i + 1];
                sr = rgbValues[i + 2];
                ctl.Reset(sr, sg, sb);
                if (ctl.IsGray)
                {
                    continue;
                }
                ctl.SetChannelLightnessOffset();
                rgbValues[i] = ctl.B;
                rgbValues[i + 1] = ctl.G;
                rgbValues[i + 2] = ctl.R;
            }
            Marshal.Copy(rgbValues, 0, ptr, bytes);
            source.UnlockBits(bmpData);
        }
    }
}
